
%{
	open Namespace_ast
	open Builders
	let n_function_nestings = ref 0
%}


%token KBreak KCase KCatch KContinue KDebugger
%token KDefault KDelete KDo KElse KFinally
%token KFor KFunction KIf KIn KInstanceof
%token KNew KReturn KSwitch KThis KThrow
%token KTry KTypeof KVar KVoid KWhile KGet KSet
%token KWith KClass KConst KEnum KExport
%token KExtends KImport KSuper KNull KTrue
%token KFalse KInfinity KSelect KFrom KWhere
%token TLBrace TRBrace TLPar TRPar TLBracket
%token TRBracket TDot TSemiColon TComma TLChevron
%token TRChevron TLEqual TGEqual TNEqual
%token TDblEqual TNDblEqual TPlus TMinus TTimes
%token TDiv TMod TIncrement TDecrement TLDblChevron
%token TRDblChevron TRTrplChevron TAmp TPipe
%token TCaret TNot TTilde TAnd TOr TQuestion
%token TColon TEqual TPlusEqual TMinusEqual
%token TTimesEqual TModEqual TLDblChevronEqual
%token TRDblChevronEqual TRTrplChevronEqual
%token TAmpEqual TCaretEqual TDivEqual TArrow
%token TPreIncrement TPreDecrement KMeta KFun
%token KNamespace KUsing KPublic KProtected KPrivate
%token TEOF TTrplEqual TPipeEqual TNewLine KInline

%token <string*string> TRegex
%token <string> TIdentifier TNumber TString TOperator TPostOperator

%start <Namespace_ast.program> program

%nonassoc TRPar
%nonassoc KElse

%%

program:
	TNewLine* ; e = sourceElement*; TEOF							{e}

sourceElement:
	| s = statement 												{AStatement s}
	| o = namespace													{ANamespace o}
(*	| d = functionDeclaration										{AFunctionDeclaration d}*) (* Moved in statement. Not ECMAScript *) (* Modif #1 *)

endstmt:
	| TSemiColon ; TNewLine*										{}
	| TNewLine+
	| TEOF															{}

realIdentifier:
	| i = TIdentifier												{i}
	| KNamespace													{"namespace"}
	| KSelect														{"select"}
	| KFrom															{"from"}
	| KWhere														{"where"}
(*	| KMeta															{"meta"}*)
(*	| KPublic														{"public"}
	| KPrivate														{"private"}*)
	| KProtected													{"protected"}
(*	| KInline														{"inline"}*)
	| KUsing														{"using"}
	| KGet															{"get"}
	| KSet															{"set"}
	| KFun															{"fun"}
	
realIdentifierNoFun:
	| i = TIdentifier												{i}
	| KNamespace													{"namespace"}
	| KSelect														{"select"}
	| KFrom															{"from"}
	| KWhere														{"where"}
(*	| KMeta															{"meta"}*)
(*	| KPublic														{"public"}
	| KPrivate														{"private"}*)
	| KProtected													{"protected"}
(*	| KInline														{"inline"}*)
	| KUsing														{"using"}
	| KGet															{"get"}
	| KSet															{"set"}

identifier:
	| i = realIdentifier ; TNewLine*									{i}

kfunction: KFunction													{incr n_function_nestings}
kfun : KFun															{incr n_function_nestings}

modifier:
	| KPublic														{false}
	| KPrivate														{true}

functionDeclaration:
	m = modifier? ; u=KMeta? ; t=KInline? ; kfunction ; TNewLine* ;
	i = identifier ;
	TLPar ; f = formalParameterList? ;
	TRPar ; TNewLine* ; TLBrace ; TNewLine* ; b = functionBody ;
	TRBrace	; 														{((match m with
																		| None -> !n_function_nestings > 0
																		| Some b -> b),
																	(match u with 
																		| None -> false
																		| Some _ -> true),
																	(match t with 
																		| None -> false
																		| Some _ -> true),
																	i, (match f with
																		| None -> []
																		| Some f -> f), b)}

functionExpression:
	t=KInline? ; kfunction ; TNewLine* ; i = identifier? ;
	TLPar ; f = formalParameterList? ;
	TRPar ; TNewLine*; TLBrace ; TNewLine* ; b = functionBody ;
	TRBrace ; 			 											{((match t with 
																		| None -> false
																		| Some _ -> true),
																	i, (match f with
																		| None -> []
																		| Some f -> f), b)}
(* t=KInline? *)
%inline shortFunctionExpression:
	| kfun ;  f = shortParameters ; e = conditionalExpression ;	{decr n_function_nestings; build_function None (Some f) e}
	| kfun ;  e = conditionalExpressionNoUnary ;						{decr n_function_nestings; build_function None None e}

formalParameterList:
	| i = identifier ;												{[i]}
	| l = formalParameterList ; TComma ; 
	i = identifier													{l@[i]}
	

%inline shortParameters:
	| l = nonempty_list(realIdentifier) ; TArrow	{l}
	
functionBody:
	s = sourceElement*												{decr n_function_nestings; s}

statement :
	| o = operatorAssignment										{AOperatorAssignment o}
	| o = operatorUnassignment										{AOperatorUnassignment o}
	| b = block				 										{ABlock b}
	| d = functionDeclaration										{AFuncDeclaration d}	
																	(* Moved from sourceElement. Not ECMAScript *) (* Modif #1 *)
	| s = variableStatement											{AVariableStatement s}
	| c = classStatement											{AClassStatement c}
	| s = constStatement											{AConstStatement s}		(* Added const declarations *)
	| TSemiColon ; TNewLine*										{AEmptyStatement}
	| e = expressionStatement										{AExpressionStatement e}
	| s = ifStatement												{AIfStatement s}
	| s = iterationStatement										{AIterationStatement s}
	| s = continueStatement											{AContinueStatement s}
	| s = breakStatement											{ABreakStatement s}
	| s = returnStatement											{AReturnStatement s}
	| s = withStatement												{AWithStatement s}
	| s = labelledStatement											{ALabelledStatement s}
	| s = switchStatement											{ASwitchStatement s}
	| s = throwStatement											{AThrowStatement s}
	| s = tryStatement												{ATryStatement s}
	| KDebugger ; endstmt											{ADebuggerStatement}

namespace:
	| KNamespace ; 
		i=separated_nonempty_list(TDot, TIdentifier) ;
		TNewLine* ; TLBrace ; TNewLine* ; b = functionBody ;
		TRBrace ; TNewLine*											{i,b}

operatorAssignment:
	| s = overridableOperator ; TEqual ; 
		e = assignmentExpression ; endstmt							{s,e}

overridableOperator:
	| s = TOperator													{s}
	| TPlus															{"+"}
	| TDblEqual														{"=="}
	| TNEqual														{"!="}
	| TTrplEqual													{"==="}
	| TNDblEqual													{"!=="}
	| TAmp															{"&"}
	| TCaret														{"^"}
	| TPipe															{"|"}
	| TAnd															{"&&"}
	| TOr															{"||"}
	| TLChevron														{"<"}
	| TRChevron														{">"}
	| TLEqual														{"<="}
	| TGEqual														{">="}
	| TLDblChevron													{"<<"}
	| TRDblChevron													{">>"}
	| TRTrplChevron													{">>>"}
	| TMinus														{"-"}
	| TMod															{"%"}
	| TTimes														{"*"}
	| TDiv															{"/"}
	| TPreIncrement													{"++"}
	| TPreDecrement													{"--"}
	| TTilde														{"~"}
	| TNot															{"!"}

operatorUnassignment:
	| KDelete ; TNewLine* ; s = overridableOperator ; 
	TSemiColon ; TNewLine*											{s}

block:
	TLBrace ; TNewLine* ; s = statement*; TRBrace; TNewLine*		{s}

expressionStatement:
	e = expressionNoBraceOrFun ; endstmt							{e}

continueStatement:
	KContinue ; i = realIdentifier? ; endstmt							{i}

breakStatement:
	KBreak ; i = realIdentifier? ; endstmt								{i}

returnStatement:
	KReturn ; e = expression? ; endstmt								{e}

withStatement:
	KWith ; TNewLine* ; TLPar; e = expression ; 
	TRPar ; TNewLine* ; s = statement								{(e, s)}

classStatement:
	| m = modifier? ; u = KMeta ? ; KClass ; TNewLine* ; 
	i = TIdentifier ; ext = classExtends? ; TLBrace ; TNewLine* ; 
	e = classElement* ; TRBrace ; endstmt;							{((match m with
																			| None -> !n_function_nestings > 0
																			| Some b -> b),
																		(match u with
																			| None -> false
																			| Some _ -> true), i, ext, e)}

classExtends: KExtends ; 
	i=separated_nonempty_list(TDot, TIdentifier)					{i}

classElement:
	| s = variableStatement TSemiColon*								{ACVariableStatement s}
	| s = constStatement TSemiColon*								{ACConstStatement s}
	| f = functionDeclaration TSemiColon*							{ACFuncDeclaration f}

ifStatement:
	| KIf ; TLPar ;
	e = expression; TRPar ; TNewLine? ;
	s1 = statement ; KElse ; TNewLine? ;
	s2 = statement													{AIfElse (e, s1, s2)}

	| KIf ; TLPar ;
	e = expression ; TRPar ; TNewLine? ;
	s = statement													{AIf (e, s)}

meta: KMeta ; TNewLine*												{true}

iterationStatement:
	| KDo ; TNewLine* ; s = statement ; KWhile ; TNewLine* ;
	TLPar ; TNewLine* ; e = expression ; TRPar ; endstmt			{ADoWhile (s, e)}

	| KWhile ; TNewLine* ; TLPar ; TNewLine* ; e = expression ;
	TRPar ; TNewLine? ; s = statement								{AWhile (e, s)}

	| KFor ; TNewLine* ; TLPar ; TNewLine* ; e1 = expressionNoIn?
	TSemiColon ; TNewLine* ; e2 = expression? ; TSemiColon ;
	TNewLine* ; e3 = expression? ; TRPar ; TNewLine? ; 
	s = statement													{AFor (e1, e2, e3, s)}

	| KFor ; TNewLine* ; TLPar ; TNewLine* ; m = meta? ; 
	KVar ; TNewLine* ;
	d = variableDeclarationListNoIn ; TSemiColon ; TNewLine* ; 
	e1 = expression? ; TSemiColon ; TNewLine* ;
	e2 = expression? ; TRPar ; TNewLine? ; s = statement			{AForVar ((match m with
																		| None -> false
																		| Some _ -> true),
																		d, e1, e2, s)}

	| KFor ; TNewLine* ; TLPar ; TNewLine* ; 
	e1 = leftHandSideExpression ; KIn ; TNewLine* ; 
	e2 = expression ; TRPar ; TNewLine? ; s = statement				{AForIn (e1, e2, s)}

	| KFor ; TNewLine* ; TLPar ; TNewLine* ; m = meta? ; 
	KVar ; TNewLine* ;
	d = variableDeclarationNoIn ; KIn ; TNewLine* ;
	e = expression ; TRPar ; TNewLine? ; s = statement				{AForVarIn ((match m with
																		| None -> false
																		| Some _ -> true), d, e, s)}


labelledStatement:
	i = realIdentifier ; TColon ; s = statement						{(i, s)}

switchStatement:
	KSwitch ; TNewLine*; TLPar ; TNewLine*; e = expression ;
	TRPar ; TNewLine* ; b = caseBlock								{(e, b)}

caseBlock:
	| TLBrace ; TNewLine* ; c = caseClause* ; 
	TRBrace ; TNewLine*												{ACasesNoDefault c}
	| TLBrace ; TNewLine* ; c1 = caseClause* ;
	c2 = defaultClause ; c3 = caseClause* ; 
	TRBrace ; TNewLine*												{ACasesDefault (c1, c2, c3)}

caseClause:
	KCase ; TNewLine* ; e = expression ; TColon ; 
	TNewLine* ; s = statement*										{(e, s)}

defaultClause:
	KDefault ; TNewLine* ; TColon ; TNewLine* ; s = statement*		{s}

throwStatement:
	KThrow ; e = expression ; endstmt								{e}

tryStatement:
	| KTry ; TNewLine* ; b = block ; c = catch						{ATryCatch (b, c)}
	| KTry ; TNewLine* ; b = block ; f = finally					{ATryFinally (b, f)}
	| KTry ; TNewLine* ; b = block ; c = catch ; f = finally		{ATryCatchFinally (b, c, f)}

catch:
	KCatch ; TNewLine* ; TLPar ; TNewLine* ; i = identifier ; 
	TRPar ; TNewLine* ; b = block									{(i,b)}

finally:
	KFinally ; TNewLine*; b = block									{b}

variableStatement:
	m = modifier? ; u = KMeta? ; KVar ; TNewLine* ; 
	s = variableDeclarationList ; endstmt							{((match m with
																			| None -> !n_function_nestings > 0
																			| Some v -> v),
																		(match u with
																			| None -> false
																			| Some _ -> true),s)}

constStatement:														(* Modif #2 *)
	m = modifier? ; u = KMeta? ; KConst ; TNewLine* ; 
	s = variableDeclarationList ; endstmt							{((match m with
																			| None -> !n_function_nestings > 0
																			| Some v -> v),
																		(match u with
																			| None -> false
																			| Some _ -> true),
																		s)}

variableDeclaration:
	i = realIdentifier ; r = initializerRule? 						{(i, r)}

variableDeclarationNoIn:
	i = realIdentifier ; r = initializerRuleNoIn?					{(i, r)}

variableDeclarationList:
	| d = variableDeclaration										{[d]}
	| l = variableDeclarationList ; TComma ; TNewLine* ; 
	d = variableDeclaration 										{l@[d]}

variableDeclarationListNoIn:
	| d = variableDeclarationNoIn									{[d]}
	| l = variableDeclarationListNoIn ; TComma ; TNewLine* ; 
	d = variableDeclarationNoIn 									{l@[d]}

initializerRule:
	TEqual ; TNewLine* ; e = assignmentExpression					{e}

initializerRuleNoIn:
	TEqual ; TNewLine* ; e = assignmentExpressionNoIn				{e}
	

primaryExpression(realIdentifier):
	| KThis	;														{AThis}
	| i = realIdentifier											{AIdentifier i}
	| l = literal ; 												{ALiteral l}
	| l = arrayLiteral												{AArrayLiteral l}
	| l = comprehensionList											{AExpression l}
	| l = objectLiteral												{AObjectLiteral l}
	| TLPar ; TNewLine* ; e = expression ; TNewLine* ; TRPar ; 		{AExpression e}

primaryExpressionNoBraceOrFun(realIdentifier) :
	| KThis ; 														{AThis}
	| i = realIdentifier											{AIdentifier i}
	| l = literal ; 												{ALiteral l}
	| l = arrayLiteral												{AArrayLiteral l}
	| l = comprehensionList											{AExpression l}
	| TLPar ; TNewLine* ; e = expression ; TNewLine* ; TRPar ;		{AExpression e}

arrayLiteral:
	| TLBracket ; TNewLine* ; e = elision? ; 
	TRBracket ;														{AElisions (match e with
																		| None -> []
																		| Some e -> e)}
	| TLBracket ; TNewLine* ; e = elementList ; 
	TRBracket ; 													{AElements e}
	| TLBracket ; TNewLine* ; e1 = elementList ; 
	TComma ; TNewLine* ; e2 = elision? ; TRBracket ;				{AElementsAndElisions (e1, match e2 with
																		| None -> []
																		| Some e2 -> e2)}
comprehensionList:
	| TLBracket ; TNewLine* ; elision? ; e1 = logicalORExpression ;
	TQuestion ; TNewLine* ; 
	e3 = separated_nonempty_list(TComma, assignmentExpression) ; 
	TRBracket														{build_comprehensionList e1 e3}

elision:
	| TComma ; TNewLine* 											{[AElision]}
	| e = elision ; TComma ; TNewLine*								{e@[AElision]}

elementList:
	| e1 = elision? ; e2 = assignmentExpression						{[((match e1 with 
																		| None -> []
																		| Some e1 -> e1) , e2)]}
	| e1 = elementList ; TComma ; TNewLine* ; e2 = elision? ;
	e3 = assignmentExpression										{e1@[((match e2 with
																		| None -> []
																		| Some e2 -> e2),e3)]}

objectLiteral:
	| TLBrace ; TNewLine* ; TRBrace ;								{[]}
	| TLBrace ; TNewLine* ; l = propertyNameAndValueList ; 
	TRBrace ; 														{l}
	| TLBrace ; TNewLine* ; l = propertyNameAndValueList ; 
	TComma; TNewLine* ; TRBrace ; 									{l}

propertyNameAndValueList:
	| a = propertyAssignment										{[a]}
	| l = propertyNameAndValueList ; TComma ; TNewLine* ;
	a = propertyAssignment											{l@[a]}
	
kget: KGet															{incr n_function_nestings}
kset: KSet															{incr n_function_nestings}

propertyAssignment:
	| p = propertyName ; TColon ; TNewLine* ; 
	e = assignmentExpression; TNewLine* 							{APropAssignment (p, e)}

	| kget ; TNewLine* ; p = propertyName ; TNewLine* ;
	TLPar ; TNewLine* ; TRPar ; TNewLine* ;
	TLBrace ; b = functionBody ; TRBrace ; TNewLine*				{APropGet (p, b)}

	| kset ; TNewLine* ; p = propertyName ; TNewLine* ; TLPar ; 
	TNewLine* ; i = identifier* ; 
	TRPar ; TNewLine* ; TLBrace ; TNewLine* ; 
	b = functionBody ; TRBrace ; TNewLine*							{APropSet (p, i, b)}

propertyName:
	| i = identifierName											{AIdentifierName i}
	| s = TString													{AStringLiteral s}
	| n = TNumber													{ANumericLiteral n}

literal:
	| KNull															{ANull}
	| b = booleanLiteral											{ABooleanLiteral b}
	| n = TNumber													{ALitNumericLiteral n}
	| s = TString													{ALitStringLiteral s}
	| s = TRegex													{ARegularExpressionLiteral s}

booleanLiteral:
	| KTrue															{true}
	| KFalse														{false}

memberExpression:
	| p = primaryExpression(realIdentifier)							{APrimaryExpr p}
	| e = functionExpression ;  									{AFunctionExpr e}
	| m = memberExpressionNoFun ; TLBracket ;
	e = expression ; TRBracket ; 									{AMemberBracketExpr (m, e)}
	| m = memberExpression ; TDot ; i = identifierName 				{AMemberDotExpr (m, i)}
	| KNew ; TNewLine* ; m = memberExpressionNoFun ; a = arguments	{AMemberNewExpr (m, a)}
	
memberExpressionNoFun:
	| p = primaryExpression(realIdentifierNoFun)					{APrimaryExpr p}
	| e = functionExpression ;  									{AFunctionExpr e}
	| m = memberExpressionNoFun ; TLBracket ;
	e = expression ; TRBracket ; 									{AMemberBracketExpr (m, e)}
	| m = memberExpression ; TDot ; i = identifierName 				{AMemberDotExpr (m, i)}
	| KNew ; TNewLine* ; m = memberExpressionNoFun ; a = arguments	{AMemberNewExpr (m, a)}
	
memberExpressionNoBraceOrFun:
	| p = primaryExpressionNoBraceOrFun(realIdentifier)				{APrimaryExpr p}
	| m = memberExpressionNoBraceOrFunNoFun ; TLBracket ;
	e = expression ; TRBracket										{AMemberBracketExpr (m, e)}
	| m = memberExpressionNoBraceOrFun ; TDot ;i = identifierName	{AMemberDotExpr (m, i)}
	| KNew ; TNewLine* ; m = memberExpressionNoFun  ; a = arguments	{AMemberNewExpr (m, a)}
	
memberExpressionNoBraceOrFunNoFun:
	| p = primaryExpressionNoBraceOrFun(realIdentifierNoFun)		{APrimaryExpr p}
	| m = memberExpressionNoBraceOrFunNoFun ; TLBracket ;
	e = expression ; TRBracket										{AMemberBracketExpr (m, e)}
	| m = memberExpressionNoBraceOrFun ; TDot ;i = identifierName	{AMemberDotExpr (m, i)}
	| KNew ; TNewLine* ; m = memberExpressionNoFun  ; a = arguments	{AMemberNewExpr (m, a)}

newExpression:
	| e = memberExpression											{AMemberExpression e}
	| KNew ; TNewLine* ; e = newExpression							{ANewMemberExpression e}

newExpressionNoBraceOrFun:
	| e = memberExpressionNoBraceOrFun								{AMemberExpression e}
	| KNew ; TNewLine* ; e = newExpression							{ANewMemberExpression e}

callExpression:
	| e = memberExpressionNoFun ; a = arguments						{ACallMemberArgs (e, a)}
	| c = callExpression ; a = arguments							{ACallExpressionArgs (c, a)}
	| c = callExpression ; TLBracket ; 
	e = expression ; TRBracket ;									{ACallExpressionExpr (c, e)}
	| c = callExpression ; TDot ; i = identifierName ;				{ACallExpressionIdent (c, i)}
	
callExpressionNoBraceOrFun:
	| e = memberExpressionNoBraceOrFun ; a = arguments				{ACallMemberArgs (e, a)}
	| c = callExpressionNoBraceOrFun ; a = arguments				{ACallExpressionArgs (c, a)}
	| c = callExpressionNoBraceOrFun ; TLBracket ;
	e = expression ; TRBracket ;		 							{ACallExpressionExpr (c, e)}
	| c = callExpressionNoBraceOrFun ; TDot ;
	i = identifierName ;											{ACallExpressionIdent (c, i)}

arguments:
	| TLPar ; TNewLine* ; TRPar ; 									{[]}
	| TLPar ; l = argumentList ; TNewLine* TRPar ;					{l}

argumentList:
	| e = assignmentExpression										{[e]}
	| l = argumentList ; TNewLine* ; TComma ;
	e = assignmentExpression										{l@[e]}

%inline leftHandSideExpression:
	| n = newExpression												{ANewExpression n}
	| c = callExpression											{ACallExpression c}

leftHandSideExpressionNoBraceOrFun:
	| n = newExpressionNoBraceOrFun									{ANewExpression n}
	| c = callExpressionNoBraceOrFun								{ACallExpression c}

postfixExpression:
	| e = leftHandSideExpression 									{ALeftHandSide e}
	| e = leftHandSideExpression ; TIncrement						{ALeftHandSideOp (e, "++")}
	| e = leftHandSideExpression ; TDecrement						{ALeftHandSideOp (e, "--")}
	| e = leftHandSideExpression ; i = TPostOperator+ ;				{build_post_ast e (List.rev i)}

postfixExpressionNoBraceOrFun:
	| e = leftHandSideExpressionNoBraceOrFun						{ALeftHandSide e}
	| e = leftHandSideExpressionNoBraceOrFun ;
	TIncrement ;													{ALeftHandSideOp (e, "++")}
	| e = leftHandSideExpressionNoBraceOrFun ;
	TDecrement ;													{ALeftHandSideOp (e, "--")}
	| e = leftHandSideExpressionNoBraceOrFun ; 
	i = TPostOperator+												{build_post_ast e (List.rev i)}

unaryExpression:
	| p = postfixExpression											{APostfixExpr p}
	| KDelete ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("delete", e)}
	| KVoid ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("void", e)}
	| KTypeof ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("typeof", e)}
	| TIncrement ; TNewLine* ; e = unaryExpression					{AOpUnaryExpr ("++", e)}
	| TDecrement ; TNewLine* ; e = unaryExpression					{AOpUnaryExpr ("--", e)}
	| TPreIncrement ; TNewLine* ; e = unaryExpression				{AOpUnaryExpr ("++", e)}
	| TPreDecrement ; TNewLine* ; e = unaryExpression				{AOpUnaryExpr ("--", e)}
	| TPlus ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("+", e)}
	| TMinus ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("-", e)}
	| TTilde ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("~", e)}
	| TNot ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("!", e)}
	| i = TOperator ;TNewLine* ; e = unaryExpression				{AOpUnaryExpr (i, e)}
	
unaryExpressionNoUnary:
	| p = postfixExpression											{APostfixExpr p}
	| KDelete ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("delete", e)}
	| KVoid ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("void", e)}
	| KTypeof ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("typeof", e)}
	| TTilde ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("~", e)}
	| TNot ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("!", e)}

unaryExpressionNoBraceOrFun:
	| p = postfixExpressionNoBraceOrFun								{APostfixExpr p}
	| KDelete ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("delete", e)}
	| KVoid ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("void", e)}
	| KTypeof ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("typeof", e)}
	| TIncrement ; TNewLine* ; e = unaryExpression					{AOpUnaryExpr ("++", e)}
	| TDecrement ; TNewLine* ; e = unaryExpression					{AOpUnaryExpr ("--", e)}
	| TPreIncrement ; TNewLine* ; e = unaryExpression				{AOpUnaryExpr ("++", e)}
	| TPreDecrement ; TNewLine* ; e = unaryExpression				{AOpUnaryExpr ("--", e)}
	| TPlus ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("+", e)}
	| TMinus ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("-", e)}
	| TTilde ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("~", e)}
	| TNot ; TNewLine* ; e = unaryExpression						{AOpUnaryExpr ("!", e)}
	| i = TOperator ;TNewLine* ; e = unaryExpression				{AOpUnaryExpr (i, e)}

multiplicativeExpression:
	| e = unaryExpression											{AUnaryExpr e}
	| e1 = multiplicativeExpression ; TTimes ; 
	e2 = unaryExpression											{ABinaryExpr ("*", e1, AUnaryExpr e2)} 
	| e1 = multiplicativeExpression ; TDiv ;
	e2 = unaryExpression											{ABinaryExpr ("/", e1, AUnaryExpr e2)} 
	| e1 = multiplicativeExpression ; TMod ;
	e2 = unaryExpression											{ABinaryExpr ("%", e1, AUnaryExpr e2)}
	
multiplicativeExpressionNoUnary:
	| e = unaryExpressionNoUnary									{AUnaryExpr e}
	| e1 = multiplicativeExpressionNoUnary ; TTimes ; 
	e2 = unaryExpression											{ABinaryExpr ("*", e1, AUnaryExpr e2)} 
	| e1 = multiplicativeExpressionNoUnary ; TDiv ;
	e2 = unaryExpression											{ABinaryExpr ("/", e1, AUnaryExpr e2)} 
	| e1 = multiplicativeExpressionNoUnary ; TMod ;
	e2 = unaryExpression											{ABinaryExpr ("%", e1, AUnaryExpr e2)}

multiplicativeExpressionNoBraceOrFun:
	| e = unaryExpressionNoBraceOrFun								{AUnaryExpr e}
	| e1 = multiplicativeExpressionNoBraceOrFun ; TTimes ; 
	e2 = unaryExpression											{ABinaryExpr ("*", e1, AUnaryExpr e2)} 
	| e1 = multiplicativeExpressionNoBraceOrFun ; TDiv 
	e2 = unaryExpression											{ABinaryExpr ("/", e1, AUnaryExpr e2)} 
	| e1 = multiplicativeExpressionNoBraceOrFun ; TMod ;
	e2 = unaryExpression											{ABinaryExpr ("%", e1, AUnaryExpr e2)}

additiveExpression:
	| e = multiplicativeExpression									{e}
	| e1 = additiveExpression ; TPlus ;
	e2 = multiplicativeExpression									{ABinaryExpr ("+", e1, e2)}
	| e1 = additiveExpression ; TMinus ;
	e2 = multiplicativeExpression									{ABinaryExpr ("-", e1, e2)}
	
additiveExpressionNoUnary:
	| e = multiplicativeExpressionNoUnary							{e}
	| e1 = additiveExpressionNoUnary ; TPlus ;
	e2 = multiplicativeExpression									{ABinaryExpr ("+", e1, e2)}
	| e1 = additiveExpressionNoUnary ; TMinus ;
	e2 = multiplicativeExpression									{ABinaryExpr ("-", e1, e2)}
	
additiveExpressionNoBraceOrFun:
	| e = multiplicativeExpressionNoBraceOrFun						{e}
	| e1 = additiveExpressionNoBraceOrFun ; TPlus ;
	e2 = multiplicativeExpression									{ABinaryExpr ("+", e1, e2)}
	| e1 = additiveExpressionNoBraceOrFun ; TMinus ;
	e2 = multiplicativeExpression									{ABinaryExpr ("-", e1, e2)}

shiftExpression:
	| e = additiveExpression										{e}
	| e1 = shiftExpression ; TLDblChevron ;
	e2 = additiveExpression											{ABinaryExpr ("<<", e1, e2)}
	| e1 = shiftExpression ; TRDblChevron ;
	e2 = additiveExpression											{ABinaryExpr (">>", e1, e2)}
	| e1 = shiftExpression ; TRTrplChevron ;
	e2 = additiveExpression											{ABinaryExpr (">>>", e1, e2)}
	
shiftExpressionNoUnary:
	| e = additiveExpressionNoUnary									{e}
	| e1 = shiftExpressionNoUnary ; TLDblChevron ;
	e2 = additiveExpression											{ABinaryExpr ("<<", e1, e2)}
	| e1 = shiftExpressionNoUnary ; TRDblChevron ;
	e2 = additiveExpression											{ABinaryExpr (">>", e1, e2)}
	| e1 = shiftExpressionNoUnary ; TRTrplChevron ;
	e2 = additiveExpression											{ABinaryExpr (">>>", e1, e2)}

shiftExpressionNoBraceOrFun:
	| e = additiveExpressionNoBraceOrFun							{e}
	| e1 = shiftExpressionNoBraceOrFun ; TLDblChevron ; 
	e2 = additiveExpression											{ABinaryExpr ("<<", e1, e2)}
	| e1 = shiftExpressionNoBraceOrFun ; TRDblChevron ; 
	e2 = additiveExpression											{ABinaryExpr (">>", e1, e2)}
	| e1 = shiftExpressionNoBraceOrFun ; TRTrplChevron ; 
	e2 = additiveExpression											{ABinaryExpr (">>>", e1, e2)}

relationalExpression:
	| e = shiftExpression											{e}
	| e1 = relationalExpression ; TLChevron ;
	e2 = shiftExpression											{ABinaryExpr ("<", e1, e2)}
	| e1 = relationalExpression ; TRChevron ;
	e2 = shiftExpression											{ABinaryExpr (">", e1, e2)}
	| e1 = relationalExpression ; TLEqual ;
	e2 = shiftExpression											{ABinaryExpr ("<=", e1, e2)}
	| e1 = relationalExpression ; TGEqual ;
	e2 = shiftExpression											{ABinaryExpr (">=", e1, e2)}
	| e1 = relationalExpression ; KInstanceof ;
	e2 = shiftExpression											{ABinaryExpr ("instanceof", e1, e2)}
	| e1 = relationalExpression ; KIn ;
	e2 = shiftExpression											{ABinaryExpr ("in", e1, e2)}
	| e1 = relationalExpression ; i = TOperator ; 
	e2 = shiftExpression											{ABinaryExpr (i, e1, e2)}
	
relationalExpressionNoUnary:
	| e = shiftExpressionNoUnary									{e}
	| e1 = relationalExpressionNoUnary ; TLChevron ;
	e2 = shiftExpression											{ABinaryExpr ("<", e1, e2)}
	| e1 = relationalExpressionNoUnary ; TRChevron ;
	e2 = shiftExpression											{ABinaryExpr (">", e1, e2)}
	| e1 = relationalExpressionNoUnary ; TLEqual ;
	e2 = shiftExpression											{ABinaryExpr ("<=", e1, e2)}
	| e1 = relationalExpressionNoUnary ; TGEqual ;
	e2 = shiftExpression											{ABinaryExpr (">=", e1, e2)}
	| e1 = relationalExpressionNoUnary ; KInstanceof ;
	e2 = shiftExpression											{ABinaryExpr ("instanceof", e1, e2)}
	| e1 = relationalExpressionNoUnary ; KIn ;
	e2 = shiftExpression											{ABinaryExpr ("in", e1, e2)}
	| e1 = relationalExpressionNoUnary ; i = TOperator ; 
	e2 = shiftExpression											{ABinaryExpr (i, e1, e2)}

relationalExpressionNoIn:
	| e = shiftExpression											{e}
	| e1 = relationalExpressionNoIn ; TLChevron ;
	e2 = shiftExpression											{ABinaryExpr ("<", e1, e2)}
	| e1 = relationalExpressionNoIn ; TRChevron ;
	e2 = shiftExpression											{ABinaryExpr (">", e1, e2)}
	| e1 = relationalExpressionNoIn ; TLEqual ;
	e2 = shiftExpression											{ABinaryExpr ("<=", e1, e2)}
	| e1 = relationalExpressionNoIn ; TGEqual ;
	e2 = shiftExpression											{ABinaryExpr (">=", e1, e2)}
	| e1 = relationalExpressionNoIn ; KInstanceof ; 
	e2 = shiftExpression											{ABinaryExpr ("instanceof", e1, e2)}
	| e1 = relationalExpressionNoIn ; i = TOperator ; 
	e2 = shiftExpression											{ABinaryExpr (i, e1, e2)}

relationalExpressionNoBraceOrFun:
	| e = shiftExpressionNoBraceOrFun								{e}
	| e1 = relationalExpressionNoBraceOrFun ; TLChevron ;
	e2 = shiftExpression											{ABinaryExpr ("<", e1, e2)}
	| e1 = relationalExpressionNoBraceOrFun ; TRChevron ;
	e2 = shiftExpression											{ABinaryExpr (">", e1, e2)}
	| e1 = relationalExpressionNoBraceOrFun ; TLEqual ;
	e2 = shiftExpression											{ABinaryExpr ("<=", e1, e2)}
	| e1 = relationalExpressionNoBraceOrFun ; TGEqual ;
	e2 = shiftExpression											{ABinaryExpr (">=", e1, e2)}
	| e1 = relationalExpressionNoBraceOrFun ; KInstanceof ; 
	e2 = shiftExpression											{ABinaryExpr ("instanceof", e1, e2)}
	| e1 = relationalExpressionNoBraceOrFun ; KIn ; 
	e2 = shiftExpression											{ABinaryExpr ("in", e1, e2)}
	| e1 = relationalExpressionNoBraceOrFun ; i = TOperator ; 
	e2 = shiftExpression											{ABinaryExpr (i, e1, e2)}
	
equalityExpression:
	| e = relationalExpression										{e}
	| e1 = equalityExpression ; TDblEqual ;
	e2 = relationalExpression										{ABinaryExpr ("==", e1, e2)}
	| e1 = equalityExpression ; TNEqual ;
	e2 = relationalExpression										{ABinaryExpr ("!=", e1, e2)}
	| e1 = equalityExpression ; TTrplEqual ;
	e2 = relationalExpression										{ABinaryExpr ("===", e1, e2)}
	| e1 = equalityExpression ; TNDblEqual ;
	e2 = relationalExpression										{ABinaryExpr ("!==", e1, e2)}

equalityExpressionNoUnary:
	| e = relationalExpressionNoUnary								{e}
	| e1 = equalityExpressionNoUnary ; TDblEqual ;
	e2 = relationalExpression										{ABinaryExpr ("==", e1, e2)}
	| e1 = equalityExpressionNoUnary ; TNEqual ;
	e2 = relationalExpression										{ABinaryExpr ("!=", e1, e2)}
	| e1 = equalityExpressionNoUnary ; TTrplEqual ;
	e2 = relationalExpression										{ABinaryExpr ("===", e1, e2)}
	| e1 = equalityExpressionNoUnary ; TNDblEqual ;
	e2 = relationalExpression										{ABinaryExpr ("!==", e1, e2)}
	
equalityExpressionNoIn:
	| e = relationalExpressionNoIn									{e}
	| e1 = equalityExpressionNoIn ; TDblEqual ;
	e2 = relationalExpressionNoIn									{ABinaryExpr ("==", e1, e2)}
	| e1 = equalityExpressionNoIn ; TNEqual ;
	e2 = relationalExpressionNoIn									{ABinaryExpr ("!=", e1, e2)}
	| e1 = equalityExpressionNoIn ; TTrplEqual ;
	e2 = relationalExpressionNoIn									{ABinaryExpr ("===", e1, e2)}
	| e1 = equalityExpressionNoIn ; TNDblEqual ;
	e2 = relationalExpressionNoIn									{ABinaryExpr ("!==", e1, e2)}

equalityExpressionNoBraceOrFun:
	| e = relationalExpressionNoBraceOrFun							{e}
	| e1 = equalityExpressionNoBraceOrFun ; TDblEqual ;
	e2 = relationalExpression										{ABinaryExpr ("==", e1, e2)}
	| e1 = equalityExpressionNoBraceOrFun ; TNEqual ;
	e2 = relationalExpression										{ABinaryExpr ("!=", e1, e2)}
	| e1 = equalityExpressionNoBraceOrFun ; TTrplEqual ;
	e2 = relationalExpression										{ABinaryExpr ("===", e1, e2)}
	| e1 = equalityExpressionNoBraceOrFun ; TNDblEqual ;
	e2 = relationalExpression										{ABinaryExpr ("!==", e1, e2)}

bitwiseANDExpression:
	| e = equalityExpression										{e}
	| e1 = bitwiseANDExpression ; TAmp ; 
	e2 = equalityExpression											{ABinaryExpr ("&", e1, e2)}
	
bitwiseANDExpressionNoUnary:
	| e = equalityExpressionNoUnary									{e}
	| e1 = bitwiseANDExpressionNoUnary ; TAmp ; 
	e2 = equalityExpression											{ABinaryExpr ("&", e1, e2)}

bitwiseANDExpressionNoIn:
	| e = equalityExpressionNoIn									{e}
	| e1 = bitwiseANDExpressionNoIn ; TAmp ;
	e2 = equalityExpressionNoIn										{ABinaryExpr ("&", e1, e2)}

bitwiseANDExpressionNoBraceOrFun:
	| e = equalityExpressionNoBraceOrFun							{e}
	| e1 = bitwiseANDExpressionNoBraceOrFun ; TAmp ;
	e2 = equalityExpression											{ABinaryExpr ("&", e1, e2)}

bitwiseXORExpression:
	| e = bitwiseANDExpression										{e}
	| e1 = bitwiseXORExpression ; TCaret ;
	e2 = bitwiseANDExpression										{ABinaryExpr ("^", e1, e2)}
	
bitwiseXORExpressionNoUnary:
	| e = bitwiseANDExpressionNoUnary								{e}
	| e1 = bitwiseXORExpressionNoUnary ; TCaret ;
	e2 = bitwiseANDExpression										{ABinaryExpr ("^", e1, e2)}

bitwiseXORExpressionNoIn:
	| e = bitwiseANDExpressionNoIn									{e}
	| e1 = bitwiseXORExpressionNoIn ; TCaret ;
	e2 = bitwiseANDExpressionNoIn									{ABinaryExpr ("^", e1, e2)}

bitwiseXORExpressionNoBraceOrFun:
	| e = bitwiseANDExpressionNoBraceOrFun							{e}
	| e1 = bitwiseXORExpressionNoBraceOrFun ; TCaret ;
	e2 = bitwiseANDExpression										{ABinaryExpr ("^", e1, e2)}

bitwiseORExpression:
	| e = bitwiseXORExpression										{e}
	| e1 = bitwiseORExpression ; TPipe ;
	e2 = bitwiseXORExpression										{ABinaryExpr ("|", e1, e2)}
	
bitwiseORExpressionNoUnary:
	| e = bitwiseXORExpressionNoUnary								{e}
	| e1 = bitwiseORExpressionNoUnary ; TPipe ;
	e2 = bitwiseXORExpression										{ABinaryExpr ("|", e1, e2)}

bitwiseORExpressionNoIn:
	| e = bitwiseXORExpressionNoIn									{e}
	| e1 = bitwiseORExpressionNoIn ; TPipe ;
	e2 = bitwiseXORExpressionNoIn									{ABinaryExpr ("|", e1, e2)}

bitwiseORExpressionNoBraceOrFun:
	| e = bitwiseXORExpressionNoBraceOrFun							{e}
	| e1 = bitwiseORExpressionNoBraceOrFun ; TPipe ;
	e2 = bitwiseXORExpression										{ABinaryExpr ("|", e1, e2)}

logicalANDExpression:
	| e = bitwiseORExpression										{e}
	| e1 = logicalANDExpression ; TAnd ;
	e2 = bitwiseORExpression										{ABinaryExpr ("&&", e1, e2)}
	
logicalANDExpressionNoUnary:
	| e = bitwiseORExpressionNoUnary								{e}
	| e1 = logicalANDExpressionNoUnary ; TAnd ;
	e2 = bitwiseORExpression										{ABinaryExpr ("&&", e1, e2)}

logicalANDExpressionNoIn:
	| e = bitwiseORExpressionNoIn									{e}
	| e1 = logicalANDExpressionNoIn ; TAnd ;
	e2 = bitwiseORExpressionNoIn									{ABinaryExpr ("&&", e1, e2)}

logicalANDExpressionNoBraceOrFun:
	| e = bitwiseORExpressionNoBraceOrFun							{e}
	| e1 = logicalANDExpressionNoBraceOrFun ; TAnd ;
	e2 = bitwiseORExpression										{ABinaryExpr ("&&", e1, e2)}

logicalORExpression:
	| e = logicalANDExpression										{e}
	| e1 = logicalORExpression ; TOr ;
	e2 = logicalANDExpression										{ABinaryExpr ("||", e1, e2)}
	
logicalORExpressionNoUnary:
	| e = logicalANDExpressionNoUnary								{e}
	| e1 = logicalORExpressionNoUnary ; TOr ;
	e2 = logicalANDExpression										{ABinaryExpr ("||", e1, e2)}

logicalORExpressionNoIn:
	| e = logicalANDExpressionNoIn									{e}
	| e1 = logicalORExpressionNoIn ; TOr ;
	e2 = logicalANDExpressionNoIn									{ABinaryExpr ("||", e1, e2)}

logicalORExpressionNoBraceOrFun:
	| e = logicalANDExpressionNoBraceOrFun							{e}
	| e1 = logicalORExpressionNoBraceOrFun ; TOr ;
	e2 = logicalANDExpression										{ABinaryExpr ("||", e1, e2)}

conditionalExpression:
	| e = logicalORExpression										{ACondBinaryExpr e}
	| e1 = logicalORExpression ; TQuestion ; TNewLine*
	e2 = assignmentExpression ; TNewLine* ; TColon ; TNewLine*
	e3 = assignmentExpression										{ACondTernaryExpr (e1, e2, e3)}
	
conditionalExpressionNoUnary:
	| e = logicalORExpressionNoUnary										{ACondBinaryExpr e}
	| e1 = logicalORExpressionNoUnary ; TQuestion ; TNewLine*
	e2 = assignmentExpression ; TNewLine* ; TColon ; TNewLine*
	e3 = assignmentExpression										{ACondTernaryExpr (e1, e2, e3)}

conditionalExpressionNoIn:
	| e = logicalORExpressionNoIn									{ACondBinaryExpr e}
	| e1 = logicalORExpressionNoIn ; TQuestion ; TNewLine* ;
	e2 = assignmentExpressionNoIn ; 
	TNewLine* ; TColon ; TNewLine* ; e3 = assignmentExpressionNoIn				{ACondTernaryExpr (e1, e2, e3)}

conditionalExpressionNoBraceOrFun:
	| e = logicalORExpressionNoBraceOrFun							{ACondBinaryExpr e}
	| e1 = logicalORExpressionNoBraceOrFun ; TQuestion ; TNewLine* ;
	e2 = assignmentExpression ; TNewLine* ; TColon ; TNewLine*
	e3 = assignmentExpression										{ACondTernaryExpr (e1, e2, e3)}

assignmentExpression:
	| e = conditionalExpression										{ACondExpr e}
	| e = shortFunctionExpression ; 								{ACondExpr e}
	| e1 = leftHandSideExpression ;
	o = assignmentOperator ; e2 = assignmentExpression				{AAssignOp (e1, o, e2)}

assignmentExpressionNoIn:
	| e = conditionalExpressionNoIn									{ACondExpr e}
	| e1 = leftHandSideExpression ;
	o = assignmentOperator ; e2 = assignmentExpressionNoIn			{AAssignOp (e1, o, e2)}

assignmentExpressionNoBraceOrFun:
	| e = conditionalExpressionNoBraceOrFun							{ACondExpr e}
	| e1 = leftHandSideExpressionNoBraceOrFun ;
	o = assignmentOperator ; e2 = assignmentExpression				{AAssignOp (e1, o, e2)}

assignmentOperator:
	| TEqual														{"="}
	| TTimesEqual													{"*="}
	| TDivEqual														{"/="}
	| TModEqual														{"%="}
	| TPlusEqual													{"+="}
	| TMinusEqual													{"-="}
	| TLDblChevronEqual												{"<<="}
	| TRDblChevronEqual												{">>="}
	| TRTrplChevronEqual											{">>>="}
	| TAmpEqual														{"&="}
	| TCaretEqual													{"^="}
	| TPipeEqual													{"|="}
	
expression:
	| e = assignmentExpression										{[e]}
	| e1 = expression ; TComma ;
	e2 = assignmentExpression										{e1@[e2]}

expressionNoIn:
	| e = assignmentExpressionNoIn									{[e]}
	| e1 = expressionNoIn ; TComma ;
	e2 = assignmentExpressionNoIn									{e1@[e2]}

expressionNoBraceOrFun:
	| e = assignmentExpressionNoBraceOrFun							{[e]}
	| e1 = expressionNoBraceOrFun ; TComma ;
	e2 = assignmentExpression										{e1@[e2]}

identifierName:
	| i = realIdentifier											{i}
	| KBreak														{"break"}
	| KCase															{"case"}
	| KCatch														{"catch"}
	| KContinue														{"continue"}
	| KDebugger														{"kdebugger"}
	| KDefault														{"default"}
	| KDelete														{"delete"}
	| KDo															{"do"}
	| KElse															{"else"}
	| KFinally														{"finally"}
	| KFor															{"for"}
	| KFunction														{"function"}
	| KIf															{"if"}
	| KIn															{"in"}
	| KInstanceof													{"instanceof"}
	| KNew															{"new"}
	| KReturn														{"return"}
	| KSwitch														{"switch"}
	| KThis															{"this"}
	| KThrow														{"throw"}
	| KTry															{"try"}
	| KTypeof														{"typeof"}
	| KVar															{"var"}
	| KVoid															{"void"}
	| KWhile														{"while"}
	| KWith															{"with"}
	| KClass														{"class"}
	| KConst														{"const"}
	| KEnum															{"enum"}
	| KExport														{"export"}
	| KExtends														{"extends"}
	| KImport														{"import"}
	| KSuper														{"super"}
	| KNull															{"null"}
	| KTrue															{"true"}
	| KFalse														{"false"}
	| KInfinity														{"Infinity"}


